package com.zatech.cgnci.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zatech.cgnci.project.base.context.UserContext;
import com.zatech.cgnci.project.base.enums.BillStatusEnum;
import com.zatech.cgnci.project.base.enums.BillTypeEnum;
import com.zatech.cgnci.project.base.enums.DirectionEnum;
import com.zatech.cgnci.project.base.enums.ResponseCodeEnum;
import com.zatech.cgnci.project.base.exception.GlobalException;
import com.zatech.cgnci.project.base.utils.ConvertUtils;
import com.zatech.cgnci.project.base.utils.VerifyUtils;
import com.zatech.cgnci.project.dto.*;
import com.zatech.cgnci.project.entity.*;
import com.zatech.cgnci.project.mapper.*;
import com.zatech.cgnci.project.service.*;
import com.zatech.cgnci.project.vo.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 收付费管理结算表 服务实现类
 * </p>
 *
 * @author Generator
 * @since 2025-01-15
 */
@Service
public class CgnciReceiptPaymentStatementServiceImpl extends ServiceImpl<CgnciReceiptPaymentStatementMapper, CgnciReceiptPaymentStatementDO> implements CgnciReceiptPaymentStatementService {

    @Autowired
    private CgnciReceiptPaymentBillsService receiptPaymentBillsService;
    @Autowired
    private CgnciReceiptPaymentBillsMapper billsMapper;
    @Autowired
    private CgnciPaymentInformationService paymentInformationService;
    @Autowired
    private CgnciPaymentInformationMapper paymentInformationMapper;
    @Autowired
    private CgnciReinsurancePaymentPlanService paymentPlanMapper;
    @Autowired
    private CgnciContractInvoiceMapper contractInvoiceMapper;
    @Autowired
    private CgnciProportionalLiabilityInvoiceMapper liabilityInvoiceMapper;
    @Autowired
    private CgnciReinsurancePremiumBillMapper premiumBillMapper;
    @Autowired
    private CgnciContractInvoiceService contractInvoiceService;
    @Autowired
    private CgnciClaimCaseTaskService claimCaseTaskService;
    @Autowired
    private IApprovalService approvalService;

    @Resource
    CgnciAccessoryService accessoryService;

    @Override
    public IPage<CgnciReceiptPaymentStatementVO> page(ReceiptPaymentStatementQueryDTO queryDTO) {
        return this.baseMapper.page(queryDTO.toPage(), queryDTO);
    }

    @Override
    public CgnciReceiptPaymentStatementVO queryDetailsByNumber(Long statementNumber) {
        CgnciReceiptPaymentStatementVO receiptPaymentStatementVO = new CgnciReceiptPaymentStatementVO();
        receiptPaymentStatementVO = ConvertUtils.convert(this.baseMapper.selectById(statementNumber), receiptPaymentStatementVO.getClass());
        List<CgnciReceiptPaymentBillsVO> receiptPaymentBillsVOS = receiptPaymentBillsService.queryBillsByStatementNumber(statementNumber);
        List<CgnciPaymentInformationVO> paymentInformationVOS = paymentInformationService.queryPaymentInformationByNumber(statementNumber);
        receiptPaymentStatementVO.setBillsVOList(receiptPaymentBillsVOS);
        if (CollectionUtils.isNotEmpty(paymentInformationVOS)) {
            receiptPaymentStatementVO.setPaymentInformationVOS(paymentInformationVOS);
        }
        // 文件信息
        List<CgnciAccessoryDO> accessoryList = accessoryService.list(new LambdaQueryWrapper<CgnciAccessoryDO>().eq(CgnciAccessoryDO::getBusinessId, statementNumber));
        receiptPaymentStatementVO.setAccessoryVOList(ConvertUtils.convert(accessoryList, CgnciAccessoryVO.class));
        return receiptPaymentStatementVO;
    }

    private boolean areIdsEqual(List<ReceiptPaymentBillsAddDTO> sourceList, List<CgnciReceiptPaymentBillsDO> targetList) {
        // 如果两个列表长度不同，直接返回false
        if (sourceList.size() != targetList.size()) {
            return false;
        }

        // 使用CollectionUtils的isEqualCollection方法比较两个列表
        return CollectionUtils.isEqualCollection(
                sourceList.stream().map(ReceiptPaymentBillsAddDTO::getId).collect(Collectors.toList()),
                targetList.stream().map(CgnciReceiptPaymentBillsDO::getId).collect(Collectors.toList())
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdate(PaymentStatementSaveOrUpDTO saveOrUpDTO) {
        UserEntity user = UserContext.getUser();
        CgnciReceiptPaymentStatementDO paymentStatementDO = ConvertUtils.convert(saveOrUpDTO, CgnciReceiptPaymentStatementDO.class);
        List<ReceiptPaymentBillsAddDTO> billsAddDTOS = saveOrUpDTO.getBillsList();
        if (paymentStatementDO.getDirection().equals(DirectionEnum.COLLECTION.getCode())) {
            paymentStatementDO.setStatus(BillStatusEnum.COLLECTION_CONFIRMATION.getCode());
        } else {
            if (saveOrUpDTO.getStatementNumber() != null && !saveOrUpDTO.getStatus().equals(BillStatusEnum.REJECT.getCode())) {
                throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "审核中的数据不允许修改");
            }
            String taskNo = claimCaseTaskService.generateTaskNo();
            // 创建任务,绑定工作流formId. 并且关联工作台的跳转地址url以及参数
            ApprovalInfoVO infoVO = approvalService.create(FlowTaskCreateDTO.builder().approvalConfigGroupId("016").formId(taskNo).formNo(taskNo)
                    .redirectionUrl("/api/claim/reserve/task/detailTask").redirectionParam(taskNo).redirectionDesc("收付费管理付款申请").build());
            FlowTaskSubmitDTO flowTaskDTO = new FlowTaskSubmitDTO();
            flowTaskDTO.setApprovalInfoId(infoVO.getApprovalInfoId());
            flowTaskDTO.setFormId(String.valueOf(taskNo));
            approvalService.submit(flowTaskDTO);
            paymentStatementDO.setStatus(BillStatusEnum.REVIEWED.getCode());
            paymentStatementDO.setTaskNo(taskNo);
        }
        String numbers = billsAddDTOS.stream()
                .map(ReceiptPaymentBillsAddDTO::getInvoiceNumber) // 获取每个对象的 id
                .map(Object::toString)                  // 将 id 转换为字符串（如果 id 不是字符串类型）
                .collect(Collectors.joining(","));      // 使用逗号连接
        paymentStatementDO.setInvoiceNumber(numbers);
        paymentStatementDO.setBillRecipient(billsAddDTOS.get(0).getBillRecipient());
        paymentStatementDO.setCreateUser(user.getNameAndCode());
        paymentStatementDO.setCreateTime(new Date());
        this.saveOrUpdate(paymentStatementDO);
        Long statementNumber = paymentStatementDO.getStatementNumber();
        LambdaUpdateWrapper<CgnciReceiptPaymentBillsDO> updateStatus = Wrappers.lambdaUpdate();
        updateStatus.eq(CgnciReceiptPaymentBillsDO::getStatementNumber, statementNumber).set(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode())
                .set(CgnciReceiptPaymentBillsDO::getStatementNumber, null);
        receiptPaymentBillsService.update(updateStatus);
        if (paymentStatementDO.getDirection().equals(DirectionEnum.PAYMENT.getCode())) {
            // 分组invoiceNumber
            Map<String, List<ReceiptPaymentBillsAddDTO>> groupingByInvoiceNumber = billsAddDTOS.stream().collect(Collectors.groupingBy(ReceiptPaymentBillsAddDTO::getInvoiceNumber));
            groupingByInvoiceNumber.forEach((invoiceNumber, billList) -> {
                // 通过invoiceNumber查询未结算的数据
                List<CgnciReceiptPaymentBillsDO> contractInvoiceDOList = receiptPaymentBillsService.list(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                        .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber)
                        .eq(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode()));
                // 对比选中的billList与contractInvoiceDOList的id是否一致
                if (areIdsEqual(billList, contractInvoiceDOList)) {
                    // 如果相等,根据invoiceNumber 全部更新为已结算
                    LambdaUpdateWrapper<CgnciReceiptPaymentBillsDO> updateWrapper = Wrappers.lambdaUpdate();
                    updateWrapper.eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber).set(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.IN_SETTLEMENT.getCode())
                            .set(CgnciReceiptPaymentBillsDO::getStatementNumber, statementNumber);
                    receiptPaymentBillsService.update(updateWrapper);
                    LambdaUpdateWrapper<CgnciReinsurancePaymentPlanDO> updateWrapper1 = Wrappers.lambdaUpdate();
                    updateWrapper1.eq(CgnciReinsurancePaymentPlanDO::getInvoiceNumber, invoiceNumber)
                            .set(CgnciReinsurancePaymentPlanDO::getActualPaymentDate, new Date());
                    paymentPlanMapper.update(updateWrapper1);
                } else {
                    // 如果不相等,选中的更新为已部分结算
                    List<CgnciReceiptPaymentBillsDO> billDOList = ConvertUtils.convert(billList, CgnciReceiptPaymentBillsDO.class);
                    billDOList.forEach(bill -> {
                        bill.setStatus(BillStatusEnum.IN_SETTLEMENT.getCode());
                        bill.setStatementNumber(statementNumber);
                        LambdaUpdateWrapper<CgnciReinsurancePaymentPlanDO> updateWrapper = Wrappers.lambdaUpdate();
                        updateWrapper.eq(CgnciReinsurancePaymentPlanDO::getInvoiceNumber, bill.getInvoiceNumber())
                                .eq(CgnciReinsurancePaymentPlanDO::getPaymentPeriod, bill.getPaymentPeriod()).set(CgnciReinsurancePaymentPlanDO::getActualPaymentDate, new Date());
                        paymentPlanMapper.update(updateWrapper);
                    });
                    receiptPaymentBillsService.updateBatchById(billDOList);
                }
            });
            //更新账单数据
            billsAddDTOS.forEach(this::updatePaymentBills);
        } else {
            // 分组invoiceNumber
            Map<String, List<ReceiptPaymentBillsAddDTO>> groupingByInvoiceNumber = billsAddDTOS.stream().collect(Collectors.groupingBy(ReceiptPaymentBillsAddDTO::getInvoiceNumber));
            groupingByInvoiceNumber.forEach((invoiceNumber, billList) -> {
                // 通过invoiceNumber查询未结算的数据
                List<CgnciReceiptPaymentBillsDO> contractInvoiceDOList = receiptPaymentBillsService.list(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                        .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber)
                        .eq(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode()));
                // 对比选中的billList与contractInvoiceDOList的id是否一致
                if (areIdsEqual(billList, contractInvoiceDOList)) {
                    // 如果相等,根据invoiceNumber 全部更新为已结算
                    LambdaUpdateWrapper<CgnciReceiptPaymentBillsDO> updateWrapper = Wrappers.lambdaUpdate();
                    updateWrapper.eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber).set(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.SETTLED.getCode())
                            .set(CgnciReceiptPaymentBillsDO::getStatementNumber, statementNumber);
                    receiptPaymentBillsService.update(updateWrapper);
                    LambdaUpdateWrapper<CgnciReinsurancePaymentPlanDO> updateWrapper1 = Wrappers.lambdaUpdate();
                    updateWrapper1.eq(CgnciReinsurancePaymentPlanDO::getInvoiceNumber, invoiceNumber)
                            .set(CgnciReinsurancePaymentPlanDO::getActualPaymentDate, new Date());
                    paymentPlanMapper.update(updateWrapper1);
                } else {
                    // 如果不相等,选中的更新为已部分结算
                    List<CgnciReceiptPaymentBillsDO> billDOList = ConvertUtils.convert(billList, CgnciReceiptPaymentBillsDO.class);
                    billDOList.forEach(bill -> {
                        bill.setStatus(BillStatusEnum.SECTION.getCode());
                        bill.setStatementNumber(statementNumber);
                        LambdaUpdateWrapper<CgnciReinsurancePaymentPlanDO> updateWrapper = Wrappers.lambdaUpdate();
                        updateWrapper.eq(CgnciReinsurancePaymentPlanDO::getInvoiceNumber, bill.getInvoiceNumber())
                                .eq(CgnciReinsurancePaymentPlanDO::getPaymentPeriod, bill.getPaymentPeriod()).set(CgnciReinsurancePaymentPlanDO::getActualPaymentDate, new Date());
                        paymentPlanMapper.update(updateWrapper);
                    });
                    receiptPaymentBillsService.updateBatchById(billDOList);

                }
            });
            //更新账单数据
            billsAddDTOS.forEach(this::updatePaymentBills);

        }
        if (paymentStatementDO.getDirection().equals(DirectionEnum.COLLECTION.getCode())) {
            List<PaymentInformationUpdateDTO> paymentInformationDTOS = saveOrUpDTO.getPaymentInformationList();
            paymentInformationMapper.delete(new LambdaQueryWrapper<CgnciPaymentInformationDO>().eq(CgnciPaymentInformationDO::getStatementNumber, paymentStatementDO.getStatementNumber()));
            for (PaymentInformationUpdateDTO informationUpdateDTO : paymentInformationDTOS) {
                CgnciPaymentInformationDO paymentInformationDO = ConvertUtils.convert(informationUpdateDTO, CgnciPaymentInformationDO.class);
                paymentInformationDO.setStatementNumber(paymentStatementDO.getStatementNumber());
                paymentInformationDO.setCreateUser(paymentStatementDO.getCreateUser());
                paymentInformationDO.setCreateTime(new Date());
                paymentInformationMapper.insert(paymentInformationDO);
            }
        }
        // 文件信息
        List<CgnciAnnualInsurePlanSaveOrUpdateDTO.AccessoryDTO> accessoryDTOList = saveOrUpDTO.getAccessoryDTOList();
        if (VerifyUtils.isNotEmpty(accessoryDTOList)) {
            List<CgnciAccessoryDO> accessoryDOList = ConvertUtils.convert(accessoryDTOList, CgnciAccessoryDO.class);
            accessoryDOList.forEach(accessory -> {
                accessory.setBusinessId(paymentStatementDO.getStatementNumber());
                accessory.setCreateUser(user.getNameAndCode());
                accessory.setUpdateUser(user.getNameAndCode());
            });
            accessoryService.saveOrUpdateBatch(accessoryDOList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approve(PaymentStatementExamineDTO flowTaskDTO) {
        UserEntity user = UserContext.getUser();
        if (flowTaskDTO.getExamineCode().equals("01")) {
            FlowTaskApprovalDTO approvalDTO = new FlowTaskApprovalDTO();
            approvalDTO.setFormNo(flowTaskDTO.getTaskNo());
            approvalDTO.setFormId(flowTaskDTO.getTaskNo());
            FlowTaskVO approve = approvalService.approve(approvalDTO);
            if (1 == approve.getIsEnd()) {

                CgnciReceiptPaymentStatementDO paymentStatementDO = new CgnciReceiptPaymentStatementDO();
                paymentStatementDO.setStatementNumber(flowTaskDTO.getStatementNumber());
                paymentStatementDO.setStatus(BillStatusEnum.PAYMENT_CONFIRMATION.getCode());
                this.baseMapper.updateById(paymentStatementDO);
                CgnciReceiptPaymentBillsDO updateDO = new CgnciReceiptPaymentBillsDO();
                updateDO.setStatus(BillStatusEnum.SETTLED.getCode());
                updateDO.setUpdateUser(user.getNameAndCode());
                //更新账单数据
                billsMapper.update(updateDO, new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                        .eq(CgnciReceiptPaymentBillsDO::getStatementNumber, flowTaskDTO.getStatementNumber()));
                List<ReceiptPaymentBillsAddDTO> billsList = flowTaskDTO.getBillsList();
                for (ReceiptPaymentBillsAddDTO billsAddDTO : billsList) {
                    updatePaymentBills(billsAddDTO);
                }
            } else {
                CgnciReceiptPaymentStatementDO paymentStatementDO = new CgnciReceiptPaymentStatementDO();
                paymentStatementDO.setStatementNumber(flowTaskDTO.getStatementNumber());
                paymentStatementDO.setStatus(BillStatusEnum.CHECKING.getCode());
                this.baseMapper.updateById(paymentStatementDO);
                CgnciReceiptPaymentBillsDO paymentBillsDO = new CgnciReceiptPaymentBillsDO();
                paymentBillsDO.setStatementNumber(flowTaskDTO.getStatementNumber());
                paymentBillsDO.setStatus(BillStatusEnum.CHECKING.getCode());
                paymentBillsDO.setUpdateUser(user.getNameAndCode());
                billsMapper.update(paymentBillsDO, new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                        .eq(CgnciReceiptPaymentBillsDO::getStatementNumber, flowTaskDTO.getStatementNumber()));
            }
        } else {
            CgnciReceiptPaymentStatementDO paymentStatementDO = new CgnciReceiptPaymentStatementDO();
            paymentStatementDO.setStatementNumber(flowTaskDTO.getStatementNumber());
            paymentStatementDO.setStatus(BillStatusEnum.REJECT.getCode());
            this.baseMapper.updateById(paymentStatementDO);
            CgnciReceiptPaymentBillsDO paymentBillsDO = new CgnciReceiptPaymentBillsDO();
            paymentBillsDO.setStatementNumber(flowTaskDTO.getStatementNumber());
            paymentBillsDO.setStatus(BillStatusEnum.REJECT.getCode());
            paymentBillsDO.setUpdateUser(user.getNameAndCode());
            billsMapper.update(paymentBillsDO, new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                    .eq(CgnciReceiptPaymentBillsDO::getStatementNumber, flowTaskDTO.getStatementNumber()));
        }
    }

    private void updatePaymentBills(ReceiptPaymentBillsAddDTO billsAddDTO) {
        UserEntity user = UserContext.getUser();
        if (billsAddDTO.getBillType().equals(BillTypeEnum.CONTRACT_INVOICE.getCode())) {
            CgnciContractInvoiceDO cgnciContractInvoiceDO = new CgnciContractInvoiceDO();
            cgnciContractInvoiceDO.setStatus(BillStatusEnum.SETTLED.getCode());
            cgnciContractInvoiceDO.setActualPaymentDate(new Date());
            cgnciContractInvoiceDO.setUpdateUser(user.getNameAndCode());
            contractInvoiceMapper.update(cgnciContractInvoiceDO, new LambdaQueryWrapper<CgnciContractInvoiceDO>()
                    .eq(CgnciContractInvoiceDO::getInvoiceNumber, billsAddDTO.getInvoiceNumber()));
        } else if (billsAddDTO.getBillType().equals(BillTypeEnum.PROPORTIONAL_LIABILITY_INVOICE.getCode())) {
            CgnciProportionalLiabilityInvoiceDO liabilityInvoiceDO = new CgnciProportionalLiabilityInvoiceDO();
            liabilityInvoiceDO.setStatus(BillStatusEnum.SETTLED.getCode());
            liabilityInvoiceDO.setActualPaymentDate(new Date());
            liabilityInvoiceDO.setUpdateUser(user.getNameAndCode());
            liabilityInvoiceMapper.update(liabilityInvoiceDO, new LambdaQueryWrapper<CgnciProportionalLiabilityInvoiceDO>()
                    .eq(CgnciProportionalLiabilityInvoiceDO::getInvoiceNumber, billsAddDTO.getInvoiceNumber()));
        } else if (billsAddDTO.getBillType().equals(BillTypeEnum.REINSURANCE_PREMIUM_BILL.getCode())) {
            Integer billsCount = billsMapper.selectCount(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                    .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, billsAddDTO.getInvoiceNumber())
                    .eq(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode()));
            CgnciReinsurancePremiumBillDO premiumBillDO = new CgnciReinsurancePremiumBillDO();
            if (billsCount > 0) {
                premiumBillDO.setStatus(BillStatusEnum.SECTION.getCode());
            } else {
                premiumBillDO.setStatus(BillStatusEnum.SETTLED.getCode());
            }
            premiumBillDO.setActualPaymentDate(new Date());
            premiumBillDO.setUpdateUser(user.getNameAndCode());
            premiumBillMapper.update(premiumBillDO, new LambdaQueryWrapper<CgnciReinsurancePremiumBillDO>()
                    .eq(CgnciReinsurancePremiumBillDO::getInvoiceNumber, billsAddDTO.getInvoiceNumber()));
        }
    }
}
